home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
ab20
/
ab20_archive
/
utilities
/
emulators
/
unixlib.lzh
/
select.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-22
|
4KB
|
155 lines
/* this file contains some functions for handling the heartbeat. */
#include <sys/types.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <exec/interrupts.h>
#include <devices/timer.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <functions.h>
/* our functions */
void setup_exception(void);
int alarm(int);
void cleanexit(char *, LONG);
void cleanup_exception(void);
static struct timerequest *treq = NULL;
static struct MsgPort *tport = NULL;
static BOOL OpenedTimer = FALSE;
static int setup = 0;
int eintr_signal;
extern int comm_time_to_call_heartbeat;
extern int errno;
static void setup_exception()
{
/* allocate a signal , used in select() */
if((eintr_signal = AllocSignal(-1)) == -1)
cleanexit("Could not allocate EINTR signal\n", RETURN_FAIL);
/* allocate a messageport */
if(!(tport = CreatePort(0L, 0L)))
cleanexit("Could not allocate port\n", RETURN_FAIL);
if(!(treq = (struct timerequest *)
CreateExtIO(tport, sizeof(struct timerequest))))
cleanexit("Could not allocate message\n",RETURN_FAIL);
/* open the timer device */
if(OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest* )treq, 0L))
cleanexit("Can't open timer device\n", RETURN_FAIL);
OpenedTimer = TRUE;
setup = 1;
}
/* signal installs a handler for a given signal. */
void signal(int sig, void (* handler) () )
{
register ULONG except_signal;
register struct Task *this_task;
if(!setup)
setup_exception();
except_signal = 1L << tport->mp_SigBit;
this_task = FindTask(NULL);
if(handler == SIG_IGN)
{ /* remove handler */
except_signal = this_task->tc_SigExcept;
SetExcept(0L, except_signal);
cleanup_exception();
}
else if(sig == SIGALRM)
{ /* install handler */
this_task->tc_ExceptCode = (APTR) handler;
SetExcept(except_signal, except_signal);
}
/* else do nothing .. */
}
/* clean up the mess made by a previous alarm, and set a new alarm up */
int alarm(int seconds)
{
while(GetMsg(tport))
;
if(seconds > 0) {
/* set up the new timer command */
treq->tr_node.io_Command = TR_ADDREQUEST;
treq->tr_time.tv_secs = seconds;
treq->tr_time.tv_micro = 0;
SendIO((struct IORequest *) treq);
}
else
{
/* delete out-standing request */
AbortIO((struct IORequest *) treq);
WaitIO((struct IORequest *) treq);
while(GetMsg(tport))
;
}
return 0;
}
static void cleanexit(char *s, LONG n)
{
if(*s) printf(s);
cleanup_exception();
exit(n);
}
static void cleanup_exception()
{
if(OpenedTimer) CloseDevice((struct IORequest *) treq);
OpenedTimer = 0;
if(treq) DeleteExtIO((struct IORequest *) treq);
treq = 0;
if(tport) DeletePort(tport);
tport = 0;
setup = 0;
}
/* check if any signals from the sets are available
* return -1 if failure,
* 0 if time-out
* number of ready descriptor otherwise
* I use the heartbeat as timeout, but according to the UNIX-manual, an
* interrupted select() returns the unchanged masks. But we already cleared
* the signals, so the messages would not be read next time. So just save
* the ready sockets, so we can read them next time.
*/
int select (width, readfds, writefds, exceptfds, timeout)
int width;
register fd_set *readfds, *writefds, *exceptfds;
struct timeval *timeout;
{
static fd_set saved = 0L;
/* find all ready descriptors */
if(saved) {
*readfds = saved; /* these were ready the last time already */
saved = 0L; /* not needed anymore */
}
else
*readfds = Wait(*readfds | eintr_signal);
if(*readfds & eintr_signal) {
saved = *readfds &~eintr_signal;
errno = EINTR;
return -1; /* Failure */
}
return 1; /* Well, this should be the number of ready descriptors */
}